#include <iostream>
#include <sstream>
#include <ruby.h>
#include "m3g/m3g.hpp"
#include "ruby-m3g.hpp"
using namespace m3g;
using namespace std;

void ruby_TriangleStripArray_mark (TriangleStripArray* ptr)
{
    vector<Object3D*> objs;
    extract_all_references (ptr, objs);
    for (int i = 0; i < (int)objs.size(); i++) {
        VALUE val_obj = (VALUE)objs[i]->getExportedEntity();
        if (val_obj)
            rb_gc_mark (val_obj);
    }
}

void ruby_TriangleStripArray_free (TriangleStripArray* ptr)
{
    if (valid_ptr((unsigned char*)ptr, sizeof(*ptr))) {
        __TRY__;
        ptr->~TriangleStripArray ();
        __CATCH__;
    }
    ruby_xfree (ptr);
}

VALUE ruby_TriangleStripArray_allocate (VALUE self)
{
    void* p = ruby_xmalloc (sizeof(TriangleStripArray));
    return Data_Wrap_Struct (self, ruby_TriangleStripArray_mark, ruby_TriangleStripArray_free, p);
}

VALUE ruby_TriangleStripArray_initialize (VALUE self, VALUE val_indices, VALUE val_strip_lengths)
{
   rb_check_type (val_strip_lengths, T_ARRAY);

    TriangleStripArray* p;
    Data_Get_Struct (self, TriangleStripArray, p);
    
    switch (TYPE(val_indices)) {
    case T_ARRAY: {
        int   num_indices = RARRAY_LEN(val_indices);
        int*  indices     = (int*)ruby_xmalloc(sizeof(int)*num_indices);
        for (int i = 0; i < num_indices; i++) {
            indices[i] = NUM2INT (rb_ary_entry(val_indices, i));
        }
        int  num_strips    = RARRAY_LEN(val_strip_lengths);
        int* strip_lengths = (int*)ruby_xmalloc(sizeof(int)*num_strips);
        for (int i = 0; i < num_strips; i++) {
            strip_lengths[i] = NUM2INT (rb_ary_entry(val_strip_lengths, i));
        }
        __TRY__;
        new (p) TriangleStripArray (indices, num_strips, strip_lengths);
        __CATCH__;
        ruby_xfree (indices);
        ruby_xfree (strip_lengths);
        break;
    }
    case T_FIXNUM: 
    case T_BIGNUM: {
        int   first_index       = NUM2INT (val_indices);
        int   num_strip_lengths = RARRAY_LEN(val_strip_lengths);
        int*  strip_lengths     = (int*)ruby_xmalloc(sizeof(int)*num_strip_lengths);
        for (int i = 0; i < num_strip_lengths; i++) {
            strip_lengths[i] = NUM2INT (rb_ary_entry(val_strip_lengths, i));
        }
        __TRY__;
        new (p) TriangleStripArray (first_index, num_strip_lengths, strip_lengths);
        __CATCH__;
        ruby_xfree (strip_lengths);
        break;
    }
    default: {
        rb_raise (rb_eArgError, "wrong argment type (epected Number or Array)");
    }
    }

    p->setExportedEntity ((void*)self);
    return self;
}

VALUE ruby_TriangleStripArray_print (VALUE self)
{
    VertexBuffer* p;
    Data_Get_Struct (self, VertexBuffer, p);
    ostringstream out;
    __TRY__;
    p->print (out);
    __CATCH__;
    return rb_str_new2 (out.str().c_str());
}

/**
 *
 */
void register_TriangleStripArray ()
{
    // TriangleStripArray
    rb_cTriangleStripArray  = rb_define_class_under (rb_mM3G, "TriangleStripArray",  rb_cIndexBuffer);

    rb_define_alloc_func     (rb_cTriangleStripArray, ruby_TriangleStripArray_allocate);
    rb_define_private_method (rb_cTriangleStripArray, "initialize", (VALUE(*)(...))ruby_TriangleStripArray_initialize, 2);

    rb_define_method (rb_cTriangleStripArray, "to_s",           (VALUE(*)(...))ruby_TriangleStripArray_print,          0);
}
